﻿using System.Configuration;
using System;
using System.Security.Principal;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.Security;

namespace Marbles.Data.LDAP
{
    public class LDAPMembershipProvider
    {

        public LDAPUser User
        {
            get { return this._User; }
        }

        public string Username
        {
            get { return this._Username; }
        }

        public string Domain
        {
            get { return this._Domain; }
        }

        private string _Domain = string.Empty;
        private LDAPUser _User = null;
        private string _Username = string.Empty;
        private UserAuthenticationSource _UserAuthenticationSource = UserAuthenticationSource.Web;

        public LDAPMembershipProvider(UserAuthenticationSource UserAuthenticationSource)
        {
            switch (UserAuthenticationSource)
            {
                case UserAuthenticationSource.Web:
                    ParseUsername(System.Web.HttpContext.Current.Request.LogonUserIdentity.Name);
                    break;
                case UserAuthenticationSource.Windows:
                    ParseUsername(WindowsIdentity.GetCurrent().Name);
                    break;
            }

            this._UserAuthenticationSource = UserAuthenticationSource;
            LoadUser();


        }

        public LDAPMembershipProvider()
        {
            ParseUsername(System.Web.HttpContext.Current.User.Identity.Name);
            this._UserAuthenticationSource = UserAuthenticationSource.Web;
            LoadUser();
        }

        public LDAPMembershipProvider(string Username)
        {
            ParseUsername(Username);
            this._UserAuthenticationSource = UserAuthenticationSource.Web;
            LoadUser();
        }

        public LDAPMembershipProvider(string Username, UserAuthenticationSource UserAuthenticationSource)
        {
            ParseUsername(Username);
            this._UserAuthenticationSource = UserAuthenticationSource;
            LoadUser();
        }

        public bool Authenticate(string userName, string password, string domain)
        {
            return LDAPCommunicationLayer.Authenticate(userName, password, domain);
        }

        public bool IsObjectClassMember(ObjectClass ObjectClass)
        {
            if (this._User == null) { return false; }
            return GetConnection().IsMemberofObjectClass(this._User.Username, ObjectClass);
        }

        public bool IsObjectClassMember(string ObjectClass)
        {
            if (this._User == null) { return false; }
            return GetConnection().IsMemberofObjectClass(this._User.Username, ObjectClass);
        }

        public WindowsIdentity GetCurrentIdentity()
        {
            WindowsIdentity ident = null;

            switch (this._UserAuthenticationSource)
            {
                case UserAuthenticationSource.Web:
                    ident = System.Web.HttpContext.Current.Request.LogonUserIdentity;
                    break;
                case UserAuthenticationSource.Windows:
                    ident = WindowsIdentity.GetCurrent();
                    break;
            }

            return ident;
        }

        public string[] GetGroupMembership()
        {
            List<string> groups = new List<string>();

            foreach (System.Security.Principal.IdentityReference group in GetCurrentIdentity().Groups)
            {
                groups.Add(group.Translate(typeof(System.Security.Principal.NTAccount)).ToString());
            }

            return groups.ToArray();
        }

        private LDAPCommunicationLayer GetConnection()
        {
            foreach (ConnectionStringSettings conn in System.Web.Configuration.WebConfigurationManager.ConnectionStrings)
            {
                if ((conn.ProviderName.ToLower() == "ldap") || (conn.ProviderName.ToLower() == "activedirectory"))
                {
                    return ParseConnection(conn.ConnectionString);
                }

            }

            return null;
        }

        private LDAPCommunicationLayer ParseConnection(string connection)
        {
            string[] args = connection.Split(';');
            string userid = string.Empty;
            string pwd = string.Empty;
            string host = string.Empty;
            string domain = string.Empty;

            foreach (string s in args)
            {
                string[] items = s.Split('=');

                if (items.Length > 1)
                {
                    switch (items[0].ToLower())
                    {
                        case "server": host = items[1]; break;
                        case "user id":
                            if (items[1].Contains("\\"))
                            {
                                string[] dom = items[1].Split('\\');
                                userid = dom[1];
                                domain = dom[0];
                            }
                            else { userid = items[1]; }
                            break;
                        case "pwd": pwd = items[1]; break;
                        case "domain": domain = items[1]; break;
                    }
                }
            }

            if (host != string.Empty)
            {
                return GetConnection(host, userid, pwd, domain);
            }

            return null;
        }

        private LDAPCommunicationLayer GetConnection(string host, string username, string password, string domain)
        {
            return new Marbles.Data.LDAP.LDAPCommunicationLayer(host, new System.Net.NetworkCredential(username, password, domain));
        }

        private void LoadUser()
        {
            if (this._Username != string.Empty)
            {

                this._User = GetConnection().GetUserByAccountName(this._Username);
            }
        }

        private void ParseUsername(string Identity)
        {
            string[] args = Identity.Split('\\');
            this._Username = string.Empty;
            this._Domain = string.Empty;

            if (args.Length <= 0) { return; }

            if (args.Length == 2)
            {
                this._Domain = args[0];
                this._Username = args[1];
            }
            else
            {
                this._Username = args[0];
            }
        }


    }

    public enum UserAuthenticationSource
    {
        Web, Windows
    }
}
